package vip.ola.pay.channel.telzfb;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import vip.ola.core.common.util.MyLog;
import vip.ola.core.common.util.PayDigestUtil;
import vip.ola.core.common.util.PayUtil;
import vip.ola.core.entity.PayOrder;
import vip.ola.core.entity.PayPassageAccount;
import vip.ola.pay.channel.BasePayment;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import static vip.ola.core.common.constant.Constant.UTF8;
import static vip.ola.core.common.constant.PayEnum.ERR_0010;
import static vip.ola.core.common.constant.PayEnum.ERR_0121;

@Service
public class TelzfbPaymentService extends BasePayment {

    private static final MyLog _log = MyLog.getLog(TelzfbPaymentService.class);

    private static final String ENCODING = "utf-8";

    @Override
    public String getChannelName() {
        return "telWx";
    }

    @Override
    public JSONObject pay(PayOrder payOrder) {
        try {
            _log.info("TelzfbPaymentService：" + payOrder.getChannelMchId());
            PayPassageAccount payPassageAccount = rpcCommonService.rpcPayPassageAccountService.findById(payOrder.getPassageAccountId());
            if (payPassageAccount == null || StringUtils.isBlank(payPassageAccount.getParam())) {
                return PayUtil.makeRetFail(ERR_0121);
            }
            JSONObject accountParams = JSONObject.parseObject(payPassageAccount.getParam());
            String mchId = payPassageAccount.getPassageMchId();
            String orderId = payOrder.getPayOrderId();
            String reqUrl = accountParams.getString("payUrl");
            BigDecimal amount = new BigDecimal(payOrder.getAmount());
            Map<String, Object> map = new HashMap<>();
            StringBuilder rawBuilder = new StringBuilder();
            map.put("version","V1.0");
            rawBuilder.append("version").append("=").append("V1.0").append("&");
            map.put("merchantNum",mchId);
            rawBuilder.append("merchantNum").append("=").append(mchId).append("&");
            map.put("nonce_str","unionpay");
            rawBuilder.append("nonce_str").append("=").append("unionpay").append("&");
            map.put("merMark","youspaydeposit");
            rawBuilder.append("merMark").append("=").append("youspaydeposit").append("&");
            map.put("client_ip","127.0.0.1");
            rawBuilder.append("client_ip").append("=").append("127.0.0.1").append("&");
            LocalDateTime localDateTime = LocalDateTime.now();
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            map.put("orderTime",localDateTime.format(dtf));
            map.put("payType","aliH5");
            rawBuilder.append("payType").append("=").append("aliH5").append("&");
            map.put("orderNum",orderId);
            rawBuilder.append("orderNum").append("=").append(orderId).append("&");
            map.put("amount",String.valueOf(amount));
            rawBuilder.append("amount").append("=").append(amount).append("&");
            map.put("body","purchase");
            rawBuilder.append("body").append("=").append("purchase").append("&");
            map.put("signType","MD5");
            map.put("bank_code","");
            map.put("notifyUrl",accountParams.getString("notify_url"));
            map.put("sign",getNewSign(rawBuilder,payPassageAccount.getPrivateKey()));
            _log.info("下单请求url={}，param={},json->{}",reqUrl,map,JSONObject.toJSONString(map));
            String respData = call(reqUrl,map);
            _log.info("下单返回={}",respData);
            if (respData.startsWith("http"))
            {
                int result = rpcCommonService.rpcPayOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("payUrl", respData);
                jsonObject.put("payOrderId", orderId);
                return PayUtil.makeRetSuc(jsonObject,null);
            }
            return PayUtil.makeRetFail(ERR_0010);
        }catch (Exception e){
            _log.error(e, "调用话费渠道异常。");
            return PayUtil.makeRetFail(ERR_0010);
        }
    }

    private String getNewSign(StringBuilder rawBuilder, String privateKey) {
        rawBuilder.append("key").append("=").append(privateKey).append("&");
        String result = rawBuilder.toString();
        result = result.substring(0, result.lastIndexOf("&"));
        _log.info("TelwxPaymentService Sign Before MD5:" + result);
        result = PayDigestUtil.md5(result, UTF8).toUpperCase();
        _log.info("TelwxPaymentService Sign Result:" + result);
        return result;
    }

    @Override
    public JSONObject query(PayOrder payOrder) {
        String logPrefix = "【tel充值订单查询】";
        String payOrderId = payOrder.getPayOrderId();
        String channelOrderNo = payOrder.getChannelOrderNo();
        _log.info("{}开始查询大象通道订单,payOrderId={}", logPrefix, payOrderId);
        PayPassageAccount payPassageAccount = rpcCommonService.rpcPayPassageAccountService.findById(payOrder.getPassageAccountId());
        if (payPassageAccount == null || StringUtils.isBlank(payPassageAccount.getParam())) {
            return PayUtil.makeRetFail(ERR_0121);
        }
        String mchId = payPassageAccount.getPassageMchId();
        BigDecimal amount = new BigDecimal(payOrder.getAmount());
        Map<String, Object> map = new HashMap<>();
        StringBuilder rawBuilder = new StringBuilder();
        map.put("version","V1.0");
        rawBuilder.append("version").append("=").append("V1.0").append("&");
        map.put("merchantNum",mchId);
        rawBuilder.append("merchantNum").append("=").append(mchId).append("&");
        map.put("orderNum",payOrderId);
        rawBuilder.append("orderNum").append("=").append(payOrderId).append("&");
        map.put("nonce_str","unionpay");
        rawBuilder.append("amount").append("=").append(amount).append("&");
        map.put("amount",String.valueOf(amount));
        rawBuilder.append("nonce_str").append("=").append("unionpay").append("&");
        map.put("sign",getNewSign(rawBuilder,payPassageAccount.getPrivateKey()));
        String reqUrl="http://39.108.52.248/MobileDeposit/OrderQuery.aspx";
        _log.info("查询请求url={}，param={},json->{}",reqUrl,map,JSONObject.toJSONString(map));
        String respData = call(reqUrl,map);
        _log.info("query end ,the respData->{}",respData);
        JSONObject retObj = buildRetObj();
        JSONObject resObj = JSON.parseObject(respData);
        if ("000".equals(resObj.get("resp_ErrCode"))){
            if ("已支付".equals(resObj.get("orderStatus"))){
                retObj.put("status",2);
            }else {
                retObj.put("status",1);
            }
        }else {
            retObj.put("status",1);
        }
        return retObj;
    }

    public static String getSign(Map<String,Object> map, String key){
        ArrayList<String> list = new ArrayList<String>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (null != entry.getValue() && !"".equals(entry.getValue())) {
                if (entry.getValue() instanceof JSONObject) {
                    list.add(entry.getKey() + "=" + PayDigestUtil.getSortJson((JSONObject) entry.getValue()) + "&");
                } else {
                    list.add(entry.getKey() + "=" + entry.getValue() + "&");
                }
            }
        }
        int size = list.size();
        String[] arrayToSort = list.toArray(new String[size]);
     //   Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < size; i++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result = result.substring(0, result.lastIndexOf("&"));
        result += key;
        _log.info("JdwxPaymentService Sign Before MD5:" + result);
        result = PayDigestUtil.md5(result, UTF8).toUpperCase();
        _log.info("JdwxPaymentService Sign Result:" + result);
        return result;
    }

    public static String call(String url, Map param) {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        HttpPost httpPost = new HttpPost(url);
        // 响应模型
        CloseableHttpResponse response = null;
        String responseContext = null;
        try {
            StringEntity entity = new StringEntity(JSONObject.toJSONString(param), ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 由客户端执行(发送)Get请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            if (responseEntity != null) {
                responseContext = EntityUtils.toString(responseEntity);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return responseContext;
    }

    /**
     * 将map转换成url
     *
     * @param map
     * @return
     */
    public static String getUrlParamsByMap(Map<String, String> map) {
        if (map == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            sb.append(entry.getKey() + "=" + entry.getValue());
            sb.append("&");
        }
        String s = sb.toString();
        if (s.endsWith("&")) {
            s = s.substring(0,s.length()-1);
        }
        return s;
    }
}
